import serial
import time
from statistics import stdev
from threading import Thread, Event
from typing import Optional, Callable


class TempController:
    """温度控制器（支持动态调整目标温度）"""

    def __init__(self, port: str = "/dev/ttySC1", baudrate: int = 57600):
        self.ser = serial.Serial(port, baudrate, timeout=1)
        self.stop_event = Event()
        self.target_temp = None
        self.worker_thread = None

        # 可调参数
        self.stable_thresh = 0.2  # 稳定阈值(°C)
        self.tolerance = 1.0  # 允许偏差(°C)
        self.sample_size = 10  # 稳定检测样本数
        self.temp_history = []  # 温度历史记录

        # 回调函数
        self.on_stable: Optional[Callable[[float], None]] = None
        self.on_alert: Optional[Callable[[str], None]] = None

    def start(self, initial_temp: float):
        """启动温度监控"""
        self._validate_temp(initial_temp)
        self.target_temp = initial_temp
        self.stop_event.clear()
        self.worker_thread = Thread(target=self._monitor_loop, daemon=True)
        self.worker_thread.start()

    def set_temp(self, new_temp: float):
        """动态设置目标温度"""
        self._validate_temp(new_temp)
        self.target_temp = new_temp
        self.temp_history = []  # 重置历史记录

    def _monitor_loop(self):
        """监控循环核心逻辑"""
        while not self.stop_event.is_set() and self.target_temp is not None:
            if temp := self._read_temp():
                self._update_history(temp)

                if self._is_stable():
                    stable_temp = sum(self.temp_history) / self.sample_size
                    deviation = abs(stable_temp - self.target_temp)

                    if deviation > self.tolerance:
                        msg = f"温度偏差过大！当前:{stable_temp:.1f}°C 目标:{self.target_temp}°C"
                        self._alert(msg)

                    if self.on_stable:
                        self.on_stable(stable_temp)

            time.sleep(1)

    def _read_temp(self) -> Optional[float]:
        """读取当前温度"""
        try:
            self.ser.write(b"TC1:TCACTTEMP?\r")
            return float(self.ser.readline().decode().split("=")[1])
        except (serial.SerialException, ValueError, IndexError):
            return None

    def _update_history(self, temp: float):
        """更新温度历史记录"""
        self.temp_history = [*self.temp_history[-self.sample_size + 1:], temp]

    def _is_stable(self) -> bool:
        """判断温度是否稳定"""
        return (len(self.temp_history) == self.sample_size and
                stdev(self.temp_history) <= self.stable_thresh)

    def _alert(self, msg: str):
        """触发报警"""
        if self.on_alert:
            self.on_alert(msg)
        else:
            print(f"!ALERT! {msg}")

    @staticmethod
    def _validate_temp(temp: float):
        """验证温度值有效性"""
        if not -10 <= temp <= 90:
            raise ValueError("温度超出有效范围(-10°C 到 90°C)")

    def stop(self):
        """停止监控并清理资源"""
        self.stop_event.set()
        if self.worker_thread:
            self.worker_thread.join(timeout=1)
        self.ser.close()


# 使用示例
if __name__ == "__main__":
    def stable_callback(temp: float):
        print(f"系统通知: 已达到稳定温度 {temp:.1f}°C")


    def alert_callback(msg: str):
        print(f"系统警告: {msg}")


    # 初始化控制器
    controller = TempController()
    controller.on_stable = stable_callback
    controller.on_alert = alert_callback

    try:
        # 启动监控(初始温度25°C)
        controller.start(25.0)

        # 模拟程序节点(实际使用时在业务节点调用set_temp)
        input("按回车设置温度到30°C...")
        controller.set_temp(30.0)

        input("按回车设置温度到22°C...")
        controller.set_temp(22.0)

        input("按回车结束监控...")
    finally:
        controller.stop()
